import type { GDVSceneConfig, Layer, SingleLayer } from '#/views/scenes';

import { ArcLayer } from '@deck.gl/layers/typed';
import { MapboxLayer } from '@deck.gl/mapbox/typed';
import { nanoid } from 'nanoid';

import { useSceneStore } from '#/store';
import { getRandomColor } from '#/utils';

const sceneStore = useSceneStore();

const getVectorLayerConfig = (
  source: any,
  layerName: string,
  renderType?: string,
) => {
  const layer = {
    name: layerName,
    id: `${layerName}_${nanoid()}`,
    source: source.sourceId,
    type: '',
    filter: ['all'],
    minzoom: 0,
    maxzoom: 24,
    metadata: 'mapbox-ninja:',
    layout: {
      visibility: 'visible',
    },
    paint: {},
    'source-layer': source.ptName,
    organizationType: 'singleLayer',
    isRenaming: false,
  } as any;
  if (source.sourceType === 'geojson') {
    delete layer['source-layer'];
  }
  // 如果没指定渲染类型，则表示为默认的矢量图层渲染（mvt/geojson）
  if (renderType) {
    switch (renderType) {
      case 'cluster': {
        delete layer.minzoom;
        delete layer.maxzoom;
        // delete layer.metadata
        layer.type = 'circle';
        layer.filter = ['has', 'point_count'];
        // layer.name = `${layerName}_cluster`

        break;
      }
      case 'heatmap': {
        layer.type = renderType;
        // layer.name = `${layerName}_heatmap`

        break;
      }
      case 'iconLabel': {
        layer.minzoom = 3;
        layer.type = 'symbol';
        layer.name = `${layerName}_iconLabel`;

        break;
      }
      case 'textLabel': {
        layer.minzoom = 3;
        layer.type = 'symbol';
        layer.name = `${layerName}_textLabel`;

        break;
      }
      // No default
    }
  }
  // 如果指定渲染类型，表示用于获取基于geojson的风格渲染
  else {
    layer.renderType = ['BasicMapping', 'singleValueRender'];
    const color = getRandomColor();
    if (source.geoType === 'POINT' || source.geoType === 'MULTIPOINT') {
      layer.type = 'circle';
      layer.paint = {
        'circle-color': color,
        'circle-opacity': 1,
      };
      layer.renderParams = {
        outline: 'closed',
        layout: {
          visibility: 'visible',
        },
        paint: {
          'circle-blur': 0,
          'circle-color': color,
          'circle-radius': 5,
          'circle-opacity': 100,
          'circle-stroke-color': '#ffff00',
          'circle-stroke-width': 5,
          'circle-stroke-opacity': 100,
        },
      };
    } else if (
      source.geoType === 'LINESTRING' ||
      source.geoType === 'MULTILINESTRING'
    ) {
      layer.type = 'line';
      layer.paint = {
        'line-color': color,
        'line-opacity': 1,
      };
      layer.renderParams = {
        layout: {
          'line-cap': 'butt',
          'line-join': 'miter',
          visibility: 'visible',
        },
        paint: {
          'line-blur': 0,
          'line-color': color,
          'line-opacity': 100,
          'line-width': 1,
          'line-dasharray': [],
          'line-gap-width': 0,
        },
      };
    } else {
      layer.type = 'fill';
      layer.paint = {
        'fill-color': color,
        'fill-opacity': 1,
        'fill-outline-color': '#FFFFFF',
      };
      layer.renderParams = {
        layout: {
          visibility: 'visible',
        },
        paint: {
          'fill-color': color,
          'fill-opacity': 100,
          'fill-outline-color': '#ffffff',
        },
      };
    }
  }
  return layer;
};

const getRasterLayerConfig = (source: any, layerName: string) => {
  const layer = {
    name: layerName,
    id: `${layerName}_${nanoid()}`,
    source: source.sourceId,
    type: '',
    // filter: ["all"],
    minzoom: 0,
    maxzoom: 24,
    metadata: 'mapbox-ninja:',
    layout: {
      visibility: 'visible',
    },
    paint: {},
    renderType: ['RasterMapping', 'imageRasterRender'],
    organizationType: 'singleLayer',
    isRenaming: false,
  } as any;
  if (source.sourceType === 'image' || source.sourceType === 'tiles') {
    layer.type = 'raster';
    // layer.paint = {
    //   "raster-opacity": 1, // 图片的不透明度（可选，取值范围为 0 ~ 1，默认值为 1）
    //   "raster-hue-rotate": 0, // 在色轮上旋转色相的角度（可选，默认值为 0，单位：角度）
    //   "raster-brightness-min": 0, // 图片的最小亮度（可选，取值范围为 0 ~ 1，默认值为 0）
    //   "raster-brightness-max": 1, // 图片的最大亮度（可选，取值范围为 0 ~ 1，默认值为 1）
    //   "raster-saturation": 0, // 图片的饱和度（可选，取值范围为 -1 ~ 1，默认值为 0）
    //   "raster-contrast": 0, // 图片的对比度（可选，取值范围为 -1 ~ 1，默认值为 0）
    //   "raster-resampling": "linear", // 采样方式（可选，可选值为 linear、nearest，默认值为 linear）
    //   "raster-fade-duration": 0 // 切换瓦片时的渐隐时间（可选，默认值为 300，单位：毫秒）
    // }
    if (source.fileType === 'tif') {
      layer.renderType = ['RasterMapping', 'singleBandRasterRender'];
      layer.paint = {
        'raster-opacity': 1,
        'raster-saturation': 0,
        'raster-contrast': 0,
        'raster-resampling': 'linear',
      };
      layer.renderParams = {
        band: 1,
        ramp: 'gray',
        type: 'ramp',
        paint: {
          'raster-opacity': 100,
          'raster-saturation': 0,
          'raster-contrast': 0,
          'raster-resampling': 'linear',
        },
      };
    } else {
      layer.renderType = ['RasterMapping', 'imageRasterRender'];
      layer.paint = {
        'raster-opacity': 1,
        'raster-saturation': 0,
        'raster-contrast': 0,
        'raster-resampling': 'linear',
      };
      layer.renderParams = {
        paint: {
          'raster-opacity': 100,
          'raster-saturation': 0,
          'raster-contrast': 0,
          'raster-resampling': 'linear',
        },
      };
    }
  }
  return layer;
};
const getDeckLayerConfig = (
  layerData: any,
  layerName: any,
  renderType?: any,
) => {
  let layer: any;
  if (renderType === 'OD') {
    layer = new MapboxLayer({
      id: `${layerName}_${nanoid()}`,
      type: ArcLayer,
      // type: renderType,
      data: layerData,
      pickable: false,
      greatCircle: false,
      getHeight: 1,
      getSourcePosition: [],
      getTargetPosition: [],
      getSourceColor: [255, 0, 0],
      getTargetColor: [255, 255, 0],
      getWidth: 5,
      visible: true,
      // 自定义属性
      name: `${layerName}_OD`,
      organizationType: 'singleLayer',
      isRenaming: false,
      layout: {
        visibility: 'visible',
      },
      source: '',
    });
  }
  return layer;
};

// 递归地扁平化图层树
const flattenLayers = (layerLists: Layer[]) => {
  let flattenedLayers = [] as SingleLayer[];

  layerLists.forEach((layer) => {
    // 如果当前层是 groupLayer，则递归地扁平化其内部的 layers
    if (
      layer.organizationType === 'groupLayer' &&
      Array.isArray(layer.layers)
    ) {
      flattenedLayers = [...flattenedLayers, ...flattenLayers(layer.layers)];
    } else {
      // 如果当前层是 singleLayer，则直接将其添加到扁平化的数组中
      flattenedLayers.push(layer as SingleLayer);
    }
  });
  return flattenedLayers;
};
/**
 * @description: 判断场景中某个source是否被其他图层引用
 * @param {string} sourceId
 * @param {Layer[]} layerTree 场景的图层树
 * @return {boolean}
 */
const isSourceUsedByLayer = (sourceId: string, layerTree: Layer[]): boolean => {
  const layerList = flattenLayers(layerTree);
  return layerList.some((layer) => layer.source === sourceId);
};
/**
 * @description: 获取图层树中指定图层的上一个图层
 * @param {string} layerId
 * @param {any} layerTree 图层树
 * @return {*} 返回上一个图层完整信息
 */
const getLastLayerOfTree = (layerId: string, layerTree: Layer[]): any => {
  const layerList = flattenLayers(layerTree);
  // 找到指定对象在数组中的索引
  const targetIndex = layerList.findIndex((obj) => obj.id === layerId);
  // 如果找到了指定对象并且不是数组的第一个对象，则获取它的前一个对象
  return targetIndex !== -1 && targetIndex > 0
    ? layerList[targetIndex - 1]
    : null;
};

/**
 * @description: 添加某个图层,包括复合图层的附属图层（对添加普通图层的封装）
 * @param {Layer} compositeLayer 复合图层
 * @param {any} map 地图实例
 * @param {string} beforeId 添加图层的前一个图层
 * @return {*}
 */
const addCompositeLayer = (
  compositeLayer: SingleLayer,
  map: any,
  beforeId?: string,
): void => {
  // 如果图层带注记层或图标层，添加时一并添加，且保持注记层在图标层上方一个位置，图标层在图层上方一个位置
  if (compositeLayer.labelLayer || compositeLayer.iconLayer) {
    if (compositeLayer.labelLayer) {
      map.addLayer(compositeLayer.labelLayer, beforeId);
      beforeId = compositeLayer.labelLayer.id;
    }
    if (compositeLayer.iconLayer) {
      map.addLayer(compositeLayer.iconLayer, beforeId);
      beforeId = compositeLayer.iconLayer.id;
    }
    map.addLayer(compositeLayer, beforeId);
  } else if (compositeLayer.clusterLayers) {
    // 先添加未聚合图层
    map.addLayer(compositeLayer.clusterLayers[1], beforeId);
    // 再添加注记图层
    map.addLayer(
      compositeLayer.clusterLayers[0],
      compositeLayer.clusterLayers[1]?.id,
    );
    // 再添加聚合图层
    map.addLayer(compositeLayer, compositeLayer.clusterLayers[0]?.id);
  } else {
    map.addLayer(compositeLayer, beforeId);
  }
};
/**
 * @description: 移除某个图层,包括复合图层的附属图层（对移除普通图层的封装）
 * @param {Layer} compositeLayer 复合图层
 * @param {any} map 地图实例
 * @param {any} type 移除的时机，drag时表示移动图层，不需要删除源
 * @return {*}
 */
const removeCompositeLayer = (
  compositeLayer: SingleLayer,
  map: any,
  type?: any,
): void => {
  map.removeLayer(compositeLayer.id);
  // 如果图层带注记层，同时删除注记层
  if (compositeLayer.labelLayer) {
    map.removeLayer(compositeLayer.labelLayer.id);
  }
  // 如果图层带图标层，同时删除图标层
  if (compositeLayer.iconLayer) {
    map.removeLayer(compositeLayer.iconLayer.id);
  }
  // 如果是聚合图层,同时删除附属图层
  if (compositeLayer.clusterLayers) {
    compositeLayer.clusterLayers.forEach((layer: any) => {
      map.removeLayer(layer.id);
    });
    if (type !== 'drag') {
      // 同时需要删除源
      map.removeSource(compositeLayer.source);
      sceneStore.currentSceneConfig.sources =
        sceneStore.currentSceneConfig.sources.filter(
          (item: any) => item.sourceId !== compositeLayer.source,
        );
    }
  }
};

/**
 * @description: 给地图指定图层设置样式
 * @param {any} map 地图对象
 * @param {string} layerId 图层ID
 * @param {any} paint 绘图属性
 * @param {any} layout 布局属性
 * @return {*}
 */
const applyLayerProperties = (
  map: any,
  layerId: string,
  paint: any,
  layout: any,
): void => {
  Object.keys(paint).forEach((key) => {
    map.setPaintProperty(layerId, key, paint[key]);
  });
  Object.keys(layout).forEach((key) => {
    map.setLayoutProperty(layerId, key, layout[key]);
  });
};

/**
 * @description: 获取保存时图层的配置对应的地图渲染时的真正配置
 * @param {Layer} layer
 * @return {Layer}
 */
const getTrueLayerPaintConfig = (layer: SingleLayer): SingleLayer => {
  switch (layer.type) {
    case 'circle': {
      // 防止聚合图的聚合图层没有该属性也走这段逻辑
      if (Object.prototype.hasOwnProperty.call(layer.paint, 'circle-opacity')) {
        layer.paint['circle-opacity'] /= 100;
      }
      if (Object.prototype.hasOwnProperty.call(layer.paint, 'circle-blur')) {
        layer.paint['circle-blur'] /= 7;
      }
      if (
        Object.prototype.hasOwnProperty.call(
          layer.paint,
          'circle-stroke-opacity',
        )
      ) {
        layer.paint['circle-stroke-opacity'] /= 100;
      }

      break;
    }
    case 'fill': {
      layer.paint['fill-opacity'] /= 100;

      break;
    }
    case 'line': {
      layer.paint['line-opacity'] /= 100;
      if (Object.prototype.hasOwnProperty.call(layer.paint, 'line-blur')) {
        layer.paint['line-blur'] *= 1.5;
      }

      break;
    }
    default: {
      if (
        layer.type === 'raster' &&
        layer.renderType &&
        [
          'imageRasterRender',
          'multiBandRasterRender',
          'singleBandRasterRender',
        ].includes(layer.renderType[1] as string)
      ) {
        layer.paint['raster-opacity'] /= 100;
        layer.paint['raster-saturation'] /= 100;
        layer.paint['raster-contrast'] /= 100;
      }
    }
  }
  if (layer.labelLayer) {
    layer.labelLayer.paint['text-opacity'] /= 100;
  }
  if (layer.iconLayer) {
    layer.iconLayer.paint['icon-opacity'] /= 100;
  }
  if (layer.clusterLayers) {
    const { paint } = layer.clusterLayers[1] as SingleLayer;
    paint['circle-opacity'] /= 100;
    if (Object.prototype.hasOwnProperty.call(paint, 'circle-blur')) {
      paint['circle-blur'] /= 7;
    }
    if (Object.prototype.hasOwnProperty.call(paint, 'circle-stroke-opacity')) {
      paint['circle-stroke-opacity'] /= 100;
    }
  }
  return layer;
};

/**
 * @description: 保存前对图层配置中的渲染属性进行处理,避免配置保存时因小数精度在数据库中变成字符串类型
 * @param {Layer} layer
 * @return {*}
 */
const returnViewLayerPaintConfig = (layer: SingleLayer): SingleLayer => {
  switch (layer.type) {
    case 'circle': {
      // 防止聚合图的聚合图层没有该属性也走这段逻辑
      if (Object.prototype.hasOwnProperty.call(layer.paint, 'circle-opacity')) {
        layer.paint['circle-opacity'] *= 100;
      }
      if (Object.prototype.hasOwnProperty.call(layer.paint, 'circle-blur')) {
        layer.paint['circle-blur'] *= 7;
      }
      if (
        Object.prototype.hasOwnProperty.call(
          layer.paint,
          'circle-stroke-opacity',
        )
      ) {
        layer.paint['circle-stroke-opacity'] *= 100;
      }

      break;
    }
    case 'fill': {
      layer.paint['fill-opacity'] *= 100;

      break;
    }
    case 'line': {
      layer.paint['line-opacity'] *= 100;
      if (Object.prototype.hasOwnProperty.call(layer.paint, 'line-blur')) {
        layer.paint['line-blur'] /= 1.5;
      }

      break;
    }
    default: {
      if (
        layer.type === 'raster' &&
        layer.renderType &&
        [
          'imageRasterRender',
          'multiBandRasterRender',
          'singleBandRasterRender',
        ].includes(layer.renderType[1] as string)
      ) {
        layer.paint['raster-opacity'] *= 100;
        layer.paint['raster-saturation'] *= 100;
        layer.paint['raster-contrast'] *= 100;
      }
    }
  }
  if (layer.labelLayer) {
    layer.labelLayer.paint['text-opacity'] *= 100;
  }
  if (layer.iconLayer) {
    layer.iconLayer.paint['icon-opacity'] *= 100;
  }
  if (layer.clusterLayers) {
    const { paint } = layer.clusterLayers[1] as SingleLayer;
    paint['circle-opacity'] *= 100;
    if (Object.prototype.hasOwnProperty.call(paint, 'circle-blur')) {
      paint['circle-blur'] *= 7;
    }
    if (Object.prototype.hasOwnProperty.call(paint, 'circle-stroke-opacity')) {
      paint['circle-stroke-opacity'] *= 100;
    }
  }
  return layer;
};

const getPaintArrName = (type: string) => {
  if (type === 'circle') {
    return { colorName: 'circle-color', sizeName: 'circle-radius' };
  } else if (type === 'line') {
    return { colorName: 'line-color', sizeName: 'line-width' };
  } else {
    return { colorName: 'fill-color', sizeName: '' };
  }
};

// 将唯一值等渲染的paint配置中请求回来数据类型原先为number的转回
const normalizeConfig = (config: GDVSceneConfig) => {
  config.layers.forEach((item: any) => {
    if (item.organizationType === 'singleLayer') {
      // if (item.type === 'raster') return
      if (
        item.type === 'circle' ||
        item.type === 'line' ||
        item.type === 'fill'
      ) {
        const { colorName, sizeName } = getPaintArrName(item.type);
        if (Array.isArray(item.paint[colorName])) {
          const paintArr = item.paint[colorName];
          for (let i = 1; i < paintArr.length - 1; i += 2) {
            if (
              Array.isArray(paintArr[i]) &&
              paintArr[i].length >= 3 &&
              // eslint-disable-next-line unicorn/prefer-number-properties
              !isNaN(paintArr[i][2])
            ) {
              paintArr[i][2] = Number(paintArr[i][2]);
            }
          }
        }
        if (Array.isArray(item.paint[sizeName])) {
          const paintArr = item.paint[sizeName];
          for (let i = 0; i < paintArr.length; i++) {
            if (
              i % 2 === 1 &&
              Array.isArray(paintArr[i]) &&
              paintArr[i].length >= 3 &&
              // eslint-disable-next-line unicorn/prefer-number-properties
              !isNaN(paintArr[i][2])
            ) {
              paintArr[i][2] = Number(paintArr[i][2]);
              // eslint-disable-next-line unicorn/prefer-number-properties
            } else if (i % 2 === 0 && !isNaN(paintArr[i])) {
              paintArr[i] = Number(paintArr[i]);
            }
          }
        }
      } else if (item.type === 'heatmap') {
        const paintArr = item.paint['heatmap-color'];
        for (let i = 3; i < paintArr.length - 1; i += 2) {
          // eslint-disable-next-line unicorn/prefer-number-properties
          if (!isNaN(paintArr[i])) {
            paintArr[i] = Number(paintArr[i]);
          }
        }
        const paintArr2 = item.paint['heatmap-weight'];
        // eslint-disable-next-line unicorn/prefer-number-properties
        if (!isNaN(paintArr2[5])) {
          paintArr2[5] = Number(paintArr2[5]);
        }
      }
    } else {
      if (item.id === 'group_vec_map' || item.id === 'group_img_map') return;
      item.layers.forEach((layer: any) => {
        // if (item.type === 'raster') return
        if (
          layer.type === 'circle' ||
          layer.type === 'line' ||
          layer.type === 'fill'
        ) {
          const { colorName, sizeName } = getPaintArrName(layer.type);
          if (Array.isArray(layer.paint[colorName])) {
            const paintArr = layer.paint[colorName];
            for (let i = 1; i < paintArr.length - 1; i += 2) {
              if (
                Array.isArray(paintArr[i]) &&
                paintArr[i].length >= 3 &&
                // eslint-disable-next-line unicorn/prefer-number-properties
                !isNaN(paintArr[i][2])
              ) {
                paintArr[i][2] = Number(paintArr[i][2]);
              }
            }
          }
          if (Array.isArray(layer.paint[sizeName])) {
            const paintArr = layer.paint[sizeName];
            for (let i = 0; i < paintArr.length; i++) {
              if (
                i % 2 === 1 &&
                Array.isArray(paintArr[i]) &&
                paintArr[i].length >= 3 &&
                // eslint-disable-next-line unicorn/prefer-number-properties
                !isNaN(paintArr[i][2])
              ) {
                paintArr[i][2] = Number(paintArr[i][2]);
                // eslint-disable-next-line unicorn/prefer-number-properties
              } else if (i % 2 === 0 && !isNaN(paintArr[i])) {
                paintArr[i] = Number(paintArr[i]);
              }
            }
          }
        } else if (item.type === 'heatmap') {
          const paintArr = item.paint['heatmap-color'];
          for (let i = 3; i < paintArr.length - 1; i += 2) {
            // eslint-disable-next-line unicorn/prefer-number-properties
            if (!isNaN(paintArr[i])) {
              paintArr[i] = Number(paintArr[i]);
            }
          }
          const paintArr2 = item.paint['heatmap-weight'];
          // eslint-disable-next-line unicorn/prefer-number-properties
          if (!isNaN(paintArr2[5])) {
            paintArr2[5] = Number(paintArr2[5]);
          }
        }
      });
    }
  });
  config.sprite = config.sprite ?? 'mapstudio';
  return config;
};
export {
  addCompositeLayer,
  applyLayerProperties,
  getDeckLayerConfig,
  getLastLayerOfTree,
  getPaintArrName,
  getRasterLayerConfig,
  getTrueLayerPaintConfig,
  getVectorLayerConfig,
  isSourceUsedByLayer,
  normalizeConfig,
  removeCompositeLayer,
  returnViewLayerPaintConfig,
};
